JavaScript 物件導向進階應用涉及許多複雜的概念與技巧,可以讓我們更有效地設計和開發大型應用程式。以下是一些 JavaScript 物件導向的應用範例,展示如何將物件導向技巧應用於更實際的場景中。
模組模式是一種常見的設計模式,用來建立私有變數和方法,同時只暴露必要的公開接口。這種模式在避免全域命名空間污染的同時,可以實現封裝。
const CounterModule = (function() {
let counter = 0; // 私有變數
return {
increment: function() {
counter++;
console.log(`Counter: ${counter}`);
},
reset: function() {
counter = 0;
console.log("Counter reset");
},
getCount: function() {
return counter;
}
};
})();
CounterModule.increment(); // Counter: 1
CounterModule.increment(); // Counter: 2
console.log(CounterModule.getCount()); // 2
CounterModule.reset(); // Counter reset
console.log(CounterModule.getCount()); // 0
這裡,我們使用立即執行函式(IIFE)創建了一個私有的 counter
,只能透過 increment()
、reset()
和 getCount()
進行操作,避免了全域範圍內直接訪問 counter
。
使用原型繼承可以讓我們在多個實例之間共享方法,減少內存使用,並促進程式碼重用。
function Car(make, model) {
this.make = make;
this.model = model;
}
Car.prototype.start = function() {
console.log(`${this.make} ${this.model} is starting...`);
};
Car.prototype.stop = function() {
console.log(`${this.make} ${this.model} is stopping...`);
};
const myCar = new Car('Toyota', 'Corolla');
myCar.start(); // Toyota Corolla is starting...
myCar.stop(); // Toyota Corolla is stopping...
const anotherCar = new Car('Honda', 'Civic');
anotherCar.start(); // Honda Civic is starting...
這裡,start()
和 stop()
方法被定義在 Car.prototype
上,因此這些方法可以被所有的 Car
實例共享,避免每次創建實例時重複定義這些方法。
工廠模式是一種創建物件的設計模式,用來根據不同的需求創建不同的物件,避免直接使用 new
關鍵字。
function createPerson(type, name) {
if (type === 'student') {
return new Student(name);
} else if (type === 'teacher') {
return new Teacher(name);
} else {
throw new Error('Invalid person type');
}
}
class Student {
constructor(name) {
this.name = name;
this.role = 'Student';
}
introduce() {
console.log(`Hi, I am ${this.name} and I am a ${this.role}.`);
}
}
class Teacher {
constructor(name) {
this.name = name;
this.role = 'Teacher';
}
introduce() {
console.log(`Hi, I am ${this.name} and I am a ${this.role}.`);
}
}
const student = createPerson('student', 'Alice');
const teacher = createPerson('teacher', 'Bob');
student.introduce(); // Hi, I am Alice and I am a Student.
teacher.introduce(); // Hi, I am Bob and I am a Teacher.
這裡使用工廠模式動態創建不同類型的物件,根據需求分配合適的類別,簡化了物件的生成邏輯。
單例模式確保一個類只有一個實例,並提供全域訪問點。這在需要共享全域狀態或資源(如設定、資料庫連接等)時很有用。
const Singleton = (function() {
let instance;
function createInstance() {
const obj = new Object('I am the instance');
return obj;
}
return {
getInstance: function() {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // true
在這裡,無論呼叫 Singleton.getInstance()
多少次,返回的都是同一個實例,這就是單例模式的核心特性。
策略模式允許一個物件根據需求選擇不同的算法或策略,而不需要在類內部實現所有的邏輯。這有助於將邏輯分解成可替換的單元。
class PaymentContext {
constructor(strategy) {
this.strategy = strategy;
}
execute(amount) {
return this.strategy.pay(amount);
}
}
class PayPalStrategy {
pay(amount) {
console.log(`Paying ${amount} using PayPal`);
}
}
class CreditCardStrategy {
pay(amount) {
console.log(`Paying ${amount} using Credit Card`);
}
}
const payPal = new PayPalStrategy();
const creditCard = new CreditCardStrategy();
const paymentContext = new PaymentContext(payPal);
paymentContext.execute(100); // Paying 100 using PayPal
paymentContext.strategy = creditCard; // 切換策略
paymentContext.execute(200); // Paying 200 using Credit Card
這裡的 PaymentContext
可以接受不同的支付策略(PayPalStrategy
或 CreditCardStrategy
),根據需求來執行不同的行為,而不必修改原本的代碼邏輯。
觀察者模式常見於事件驅動系統,允許物件(觀察者)訂閱其他物件(被觀察者)的變化,當狀態變化時會通知所有訂閱者。這在事件監聽、資料流更新等場景中應用廣泛。
class Subject {
constructor() {
this.observers = [];
}
addObserver(observer) {
this.observers.push(observer);
}
removeObserver(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
notifyObservers() {
this.observers.forEach(observer => observer.update());
}
}
class Observer {
constructor(name) {
this.name = name;
}
update() {
console.log(`${this.name} has been notified.`);
}
}
const subject = new Subject();
const observer1 = new Observer('Observer 1');
const observer2 = new Observer('Observer 2');
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.notifyObservers();
// Observer 1 has been notified.
// Observer 2 has been notified.
在這個範例中,Subject
可以通知所有已訂閱的 Observer
當狀態發生改變。這種設計模式非常適合處理事件驅動系統和實時數據更新。
裝飾者模式允許在不改變物件結構的情況下,動態地為物件增加新功能。這可以幫助保持類的簡單,並讓我們能夠根據需求添加功能。
class Coffee {
cost() {
return 5;
}
}
class MilkDecorator {
constructor(coffee) {
this.coffee = coffee;
}
cost() {
return this.coffee.cost() + 2;
}
}
class SugarDecorator {
constructor(coffee) {
this.coffee = coffee;
}
cost() {
return this.coffee.cost() + 1;
}
}
let myCoffee = new Coffee();
myCoffee = new MilkDecorator(myCoffee); // 添加牛奶
myCoffee = new SugarDecorator(myCoffee); // 添加糖
console.log(myCoffee.cost()); // 8
裝飾者模式允許在 Coffee
的基礎上,通過動態添加 MilkDecorator
和 SugarDecorator
增加功能,而不需要改變 Coffee
類的內部實現。